<?php


namespace report;


class Report
{

    private static $instance=null;  //创建静态单列对象变量

    protected $im;        //图对象
    protected $width;     //图片宽
    protected $height;    //图片高
    protected $PenColor;  //画笔颜色GD对象
    protected $lastPenColor; //记录上次画笔颜色#2222
    protected $backColor;   //背景颜色#ffff
    protected $marginTop = 0;  // 当前位置距离顶部多少
    protected $RowMarginTop = 0;  //当前行的距离顶部位置
    protected $tableStart = 0;    //表格开始的位置X点
    protected $tableEnd = 0;      //表格结束的位置Y点
    protected $ColMarginLeft =0;  //当前列距离表格开始位置
    protected $txtStart = 0;    //表格文字开始的右边X位置
    protected $txtTop = 0;      //表格文字开始的顶部Y位置
    protected $txtLastSize = 0; //上一次的字体大小
    protected $fontfile = __DIR__."/msyh.ttc";   //字体库

    /**
     * 构造函数
     * Report constructor.
     * @param $width
     * @param $height
     */
    private function __construct($width,$height){
        //1.创建画布，默认的背景是黑色
        $this->im =imagecreatetruecolor($width,$height);
        $this->width = $width;
        $this->height = $height;
    }

    /**
     * 单列模式
     * @param $width  画布宽
     * @param $height 画布高
     * @return Report|null
     */
    public static function getInstance($width,$height){
        if(empty(self::$instance)) {
            self::$instance=new Report($width,$height);
        }
        return self::$instance;
    }

    /**
     * 克隆函数私有化，防止外部克隆对象
     * @throws \Exception
     */
    private function __clone(){
        throw new \Exception('禁止克隆');
    }

    /**
     * function 16进制颜色转换为RGB色值
     */
    protected function hex2rgb($hexColor){
        $color=str_replace('#','',$hexColor);
        if (strlen($color)> 3){
            $rgb=array(
                'r'=>hexdec(substr($color,0,2)),
                'g'=>hexdec(substr($color,2,2)),
                'b'=>hexdec(substr($color,4,2))
            );
        }else{
            $color=str_replace('#','',$hexColor);
            $r=substr($color,0,1). substr($color,0,1);
            $g=substr($color,1,1). substr($color,1,1);
            $b=substr($color,2,1). substr($color,2,1);
            $rgb=array(
                'r'=>hexdec($r),
                'g'=>hexdec($g),
                'b'=>hexdec($b)
            );
        }
        return $rgb;
    }

    /**
     * 将像素转换为GD2的磅像素
     */
    protected function px2gd2($px){
        $lists = [4=>1, 5=>2, 7=>3, 8=>4, 9=>5, 10=>6, 11=>7, 12=>8, 14=>9, 15=>10, 16=>11, 17=>12, 18=>13, 19=>14, 21=>15, 22=>16, 23=>17, 25=>18, 26=>19, 27=>20, 28=>21, 29=>22, 30=>23, 32=>24, 33=>25, 34=>26, 35=>27, 36=>28, 38=>29, 39=>30, 40=>31, 41=>32, 43=>33, 44=>34, 46=>35, 47=>36, 48=>37, 50=>39, 51=>40, 52=>41, 53=>42, 55=>43, 56=>44, 57=>45, 58=>46, 60=>47, 62=>48, 63=>49, 64=>51, 67=>52, 68=>53, 69=>54, 70=>55, 71=>56, 72=>57, 74=>58, 75=>59, 76=>60, 77=>61, 78=>62, 79=>63, 81=>64, 83=>65, 84=>66, 85=>67, 86=>68, 88=>70, 90=>71, 91=>72, 92=>73, 93=>74];
        return $lists[$px];
    }

    /**
     * 获取文字初始坐标和尺寸
     * @param $size
     * @param $txt
     * @return array
     */
    protected function getTxtInfo($size,$txt){
        //获取文字信息
        $info = imagettfbbox($size, 0, $this->fontfile, $txt);
        $minx = min($info[0], $info[2], $info[4], $info[6]);
        $maxx = max($info[0], $info[2], $info[4], $info[6]);
        /* 计算文字初始坐标和尺寸 */
        $x = $minx;
        $w = $maxx - $minx;
        return [$x,$w];
    }

    /**
     * 设置表格背景颜色
     */
    public function backgroundColor($hexColor){
        //设置背景颜色
        $this->backColor = $hexColor;
        $rgb = $this->hex2rgb($hexColor);
        //默认是黑色背景，修改为$hexColor
        $background=imagecolorallocate($this->im,$rgb['r'],$rgb['g'],$rgb['b']);
        imagefill($this->im,0,0,$background);
    }

    /**
     * 设置画笔颜色
     * @param $color
     * @param $now boolean 当画笔是否记录
     */
    public function setPenColor($color,$now=true){
        if ($now){
            $this->lastPenColor = $color;
        }
        $rgb = $this->hex2rgb($color);
        $this->PenColor =imagecolorallocate($this->im,$rgb['r'],$rgb['g'],$rgb['b']);
    }

    /**
     * 设置报告标题
     * @param $title
     * @param $size int 字体大小
     * @param $color
     * @param $color int 距离顶部20px
     */
    public function setReportName($title,$size,$color='',$top=20){
        $size = $this->px2gd2($size);
        //获取文字信息
        list($x,$w) = $this->getTxtInfo($size,$title);
        $x += ($this->width - $w) / 2;
        //设置颜色
        if ($color!=''){
            $this->setPenColor($color);
        }
        //标题距离顶部位置
        $this->marginTop = $size+$top;
        imagettftext($this->im,$size,0,$x,$this->marginTop,$this->PenColor,$this->fontfile,$title);
    }

    /**
     * 保存图片
     * @param $savePath
     */
    public function toImage($savePath){
        imagepng($this->im,$savePath);
        imagedestroy($this->im);
    }
    

    /**
     * 画表框
     * @param $width
     * @param $height
     * @param $top
     */
    public function drawTableRectangle($width,$height,$top){
        //当前距离最顶端距离
        $this->marginTop += $top;
        //表格居中
        $this->tableStart = ($this->width - $width)/2;
        $this->tableEnd = $this->marginTop+$height;
        imagerectangle($this->im,$this->tableStart,$this->marginTop,$this->tableStart+$width, $this->tableEnd,$this->PenColor);
    }

    /**
     * 画行
     * @param $rows array 每一行的长度[w1,w2,w3]
     */
    public function drawTableRow($rows,$height){
        $this->RowMarginTop = $this->marginTop;
        foreach ($rows as $row){
            $this->RowMarginTop +=$height;
            imageline($this->im,$this->tableStart,$this->RowMarginTop,$this->tableStart+$row,$this->RowMarginTop,$this->PenColor);
        }
    }

    /**
     * 画列
     * $cols['width'] int 一列的宽
     * $cols['height']  int 可选 一列的高度
     * $cols['list'] array [['start1','length1'],['start2','length2']]
     * $cols['list'][i]['start']  断层的表格长度开始点位置
     * $cols['list'][i]['length']  断层的长度
     * @param $cols array
     */
    public function drawTableCols($cols){
        $this->ColMarginLeft = $this->tableStart;
        foreach ($cols as $col){
            //列线开始X位置
            $this->ColMarginLeft +=$col['width'];
            //画列线
            if (isset($col['height'])&&$col['height']>0){
                $colEnd = $this->marginTop+$col['height'];
                imageline($this->im,$this->ColMarginLeft,$this->marginTop,$this->ColMarginLeft,$colEnd,$this->PenColor);
            }else{
                imageline($this->im,$this->ColMarginLeft,$this->marginTop,$this->ColMarginLeft,$this->tableEnd,$this->PenColor);
            }
            //画断点列线
            if (isset($col['list'])&&is_array($col['list'])){
                //将画笔改成背景色
                $this->setPenColor($this->backColor,false);
                foreach ($col['list'] as $list){
                    $start = $this->marginTop+$list['start'];
                    $end = $start+$list['length'];
                    imageline($this->im,$this->ColMarginLeft,$start,$this->ColMarginLeft,$end,$this->PenColor);
                }
                //将画笔还原成表格色
                $this->setPenColor($this->lastPenColor,false);
            }
        }
    }

    /**
     * @param $txtList array
     * [
     *    [
     *      'size'=>'字体大小',    int   px字体默认14
     *      'w'=>'宽',    int   表格格子宽
     *      'h'=>'高',    int   表格格子高
     *      'value'=>'写入文字内容'  string
     *    ]
     * ]
     */
    public function writeTableText($txtList){
        $size = $this->px2gd2(14);          //默认给一个14px的字体大小
        //文字初始位于top位置
        $this->txtTop = $this->marginTop;
        foreach ($txtList as $list){
            //文字初始位于left位置
            $this->txtStart = $this->tableStart;
            foreach ($list as $txt){
                //如果写入的文字设置了字体大小使用写入文字的字体大小
                if (isset($txt['size'])&&$txt['size']>0){
                    $this->txtLastSize = $size;
                    $size = $this->px2gd2($txt['size']);
                }
                //获取文字信息
                list($x,$w) = $this->getTxtInfo($size,$txt['value']);
                $start =  $this->txtStart + $x + ($txt['w'] - $w) / 2;
                $end =  $this->txtTop +  ($txt['h'] - $size*2) ;
                imagettftext($this->im,$size,0,$start,$end,$this->PenColor,$this->fontfile,$txt['value']);

                //设置下一个位置
                $this->txtStart += $txt['w'];
                //恢复上一次的字体大小
                if (isset($txt['size'])&&$txt['size']>0&&$this->txtLastSize!=$size){
                    $size = $this->txtLastSize;
                }
                //如果是最后一条值设置文字距离顶部高度
                if($txt == end($list)) {
                    $this->txtTop += $txt['h'];
                }
            }
        }
    }

    /**
     * 表格写入图片
     * @param $image string 图片地址或者图片base64编码
     * @param $w  int 表格格子的宽
     * @param $h int 表格格子的高
     * @param $img_w  int 图片的宽
     * @param $img_h int 图片的高
     * @param $table_w  int 表格的宽
     * @param int $table_h int 表格的高
     */
    public function writeTableImage($image,$w,$h,$img_w,$img_h,$table_w,$table_h=0){
        //如果是地址文件否则是base64编码图片
        if (is_file($image)){
            $imgInfo = getimagesize($image);
            $imgType = image_type_to_extension($imgInfo[2], false);
            $fun = "imagecreatefrom{$imgType}";
            $im = $fun( $image);
        }else{
            $im = imagecreatefromstring(base64_decode($image));
        }

        $src_w = imagesx($im);
        $src_h = imagesy($im);
        if ($src_w>$img_w&&$src_h>$img_h){
            //创建一个新的图像源（目标图像）
            $nim = imagecreatetruecolor($img_w, $img_h);
            //执行缩放
            imagecopyresampled($nim, $im, 0, 0, 0, 0, $img_w, $img_h, $src_w, $src_h);
            $im = $nim;
        }
        $dst_x = $this->tableStart+$table_w+($w-$img_w)/2;
        $dst_y = $this->marginTop+$table_h+($h-$img_h)/2;
        imagecopymerge($this->im, $im, $dst_x, $dst_y, 0,0, $img_w,$img_h , 100);
    }

}